﻿using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using DataAccessLayer;

namespace Editor
{
    public sealed class ProtagonistPresenter : IProtagonistPresenter
    {
        private readonly IPresenterFacade Parent;

        public List<Protagonist> Model { get; set; }

        public ProtagonistPresenter(IPresenterFacade parent)
        {
            Parent = parent;
        }

        public Protagonist AddProtagonist()
        {
            int id = Parent.CreateObjectId();

            Protagonist prot = new NormalProtagonist {ID = id};

            Model.Add(prot);

            return prot;
        }
        
        public Protagonist GetProtagonist(int id)
        {
            return Model.Single(prot => prot.ID == id);
        }

        public void SaveData(int id, int hp, int power, int speed, int weaponSlots)
        {
            int index = Model.IndexOf(Model.Single(prot => prot.ID == id));

            Model[index].Hp = hp;
            Model[index].Power = power;
            Model[index].Speed = speed;
            Model[index].WeaponSlots = weaponSlots;
        }

        public void SetProtagonistPosition(int id, int x, int y)
        {
            int index = Model.IndexOf(Model.Single(prot => prot.ID == id));

            Model[index].Position = new EditorVector2(x, y);
        }

        public void SetProtagonistSourceRect(int id, int x, int y, int width, int height)
        {
            int index = Model.IndexOf(Model.Single(prot => prot.ID == id));

            Model[index].SourceRect = new EditorRect(x, y, width, height);
        }

        public bool AddWeaponToProtagonist(int protId, int weaponId, out string errMsg)
        {
            int protIndex = Model.IndexOf(Model.Single(prot => prot.ID == protId));

            List<WeaponBase> weapons = Parent.GetWeapons();

            WeaponBase weapon = weapons.Single(wpn => wpn.ID == weaponId);

            IEnumerable<WeaponBase> selectedWeapons = (from wpn in weapons
                                                       from wpnId in Model[protIndex].WeaponIds
                                                       where wpn.ID == wpnId
                                                       select wpn);

            errMsg = "";

            if (Model[protIndex].WeaponSlots < weapon.RequiredSlots &&
                (weapon.RequiredSlots + selectedWeapons.Sum(wpn => wpn.RequiredSlots) < Model[protIndex].WeaponSlots))
            {
                Model[protIndex].WeaponIds.Add(weaponId);

                return true;
            }

            errMsg = "Protagonist does not have enough weapon slots.";

            return false;
        }

        public void SetProtagonistSourceRectangle(int id, Rectangle sourceRect)
        {
            int protIndex = Model.IndexOf(Model.Single(prot => prot.ID == id));

            Model[protIndex].SourceRect = sourceRect;
        }

        public void DeleteProtagonist(int id)
        {
            int protIndex = Model.IndexOf(Model.Single(prot => prot.ID == id));

            Model.RemoveAt(protIndex);
        }

        public void SetProtagonistSprite(int id, string spriteName)
        {
            int protIndex = Model.IndexOf(Model.Single(prot => prot.ID == id));

            Model[protIndex].TextureName = spriteName;
        }

        public void SetCollisionRectangle(int id, Rectangle colRect)
        {
            int protIndex = Model.IndexOf(Model.Single(prot => prot.ID == id));

            if (Model[protIndex] is NormalProtagonist)
            {
                ((NormalProtagonist)Model[protIndex]).CollisionRectangle = colRect;
            }
            else if (Model[protIndex] is ProtagonistEx)
            {
                ((ProtagonistEx)Model[protIndex]).CollisionRectangles.Add(colRect);
            }
        }

        public void SetCollisionRectangle(int id, int colRectIndex, EditorRect colRect)
        {
            int protIndex = Model.IndexOf(Model.Single(prot => prot.ID == id));

            if (Model[protIndex] is NormalProtagonist)
            {
                ((NormalProtagonist)Model[protIndex]).CollisionRectangle = colRect;
            }
            else if (Model[protIndex] is ProtagonistEx)
            {
                ((ProtagonistEx)Model[protIndex]).CollisionRectangles[colRectIndex] = colRect;
            }
        }

        public void RemoveProtagonistCollisionRectangle(int id, int selectedIndex)
        {
            int protIndex = Model.IndexOf(Model.Single(prot => prot.ID == id));

            if (Model[protIndex] is NormalProtagonist)
            {
                ((NormalProtagonist)Model[protIndex]).CollisionRectangle = new EditorRect();
            }
            else if (Model[protIndex] is ProtagonistEx)
            {
                ((ProtagonistEx)Model[protIndex]).CollisionRectangles.RemoveAt(selectedIndex);
            }
        }

        public void SaveData(int id, AircraftStats basicStats, RectangleProperties rectProps, EditorVector2 position)
        {
            int index = Model.IndexOf(Model.Single(m => m.ID == id));

            if (index < 0) return;

            if(rectProps.CollisionRectangles.Count > 1)
            {
                if (Model[index] is NormalProtagonist)
                    Model[index] = new ProtagonistEx();

                ((ProtagonistEx)Model[index]).CollisionRectangles = rectProps.CollisionRectangles;
            }
            else if ((rectProps.CollisionRectangles.Count == 1))
            {
                if (Model[index] is ProtagonistEx)
                    Model[index] = new NormalProtagonist();

                ((NormalProtagonist)Model[index]).CollisionRectangle = rectProps.CollisionRectangles[0];
            }

            Model[index].Hp = basicStats.Hp;
            Model[index].Power = basicStats.Power;
            Model[index].Speed = basicStats.Speed;
            Model[index].WeaponSlots = basicStats.WeaponSlots;
            Model[index].Position = position;
        }
    }
}